import backtrader as bt
import numpy as np
import pandas as pd
import traceback

from indicators.KDJ import KDJ


class BollingerBand(bt.Strategy):
    # 策略参数
    params = dict(
        trailamount= 0.0,
        trailpercent=0.05,
        period=20,  # 均线周期
        look_back_days=30,
        printlog=False,
        period_ema_fast=10,
        period_ema_slow=100,
        short_window=30,
        long_window=60,
        N1=20,
        N2=50,
        N3=25,
        wave_window=20,
        wave_two_window=50,
        wave_three_window=70,
    )


    def __init__(self):
        # 存储不同数据的技术指标
        self.inds = dict()
        # 存储特定股票的订单，key为股票的代码
        self.orders = dict()
        try:
         #for i, data in enumerate(self.datas):
         for data in self.datas:
           data.N_Low = bt.ind.Lowest(data.low, period=self.p.N2)
           data.N_High=bt.ind.Highest(data.low, period=self.p.N1)
           data.mas = dict()
           print(len(data.close))
           data.rsi = bt.indicators.RelativeStrengthIndex()
           data.profit= 0
           data.short_ma = bt.indicators.SMA(data.close, period=self.p.short_window)
           data.long_ma = bt.indicators.SMA(data.close, period=self.p.long_window)
           # 五日移动平均线
           data.sma2 = bt.indicators.SimpleMovingAverage(data, period=2)

           data.lines.top =bt.indicators.BollingerBands(data, period=self.p.N1).top
           data.lines.bot = bt.indicators.BollingerBands(data, period=self.p.N1).bot
           data.K = KDJ(data).lines.K
           data.D = KDJ(data).lines.D
           data.J = KDJ(data).lines.J


        except Exception as e:
            traceback.print_exc()

        #遍历所有股票,计算20日均线
        #for data in self.datas:

    def notify_order(self, order):
        """
        订单状态处理

        Arguments:
            order {object} -- 订单状态
        """
        if order.status in [order.Submitted, order.Accepted]:
            # 如订单已被处理，则不用做任何事情
            return

        # 检查订单是否完成
        if order.status in [order.Completed]:
            if order.isbuy():
                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
                #print('BUY成交, 执行价={0}, {1}'.format(order.executed.price, order.executed.size))
            #elif order.issell():
                #print('SELL成交, 执行价={0}, {1}'.format(order.executed.price, order.executed.size))
            self.bar_executed = len(self)
        # 订单因为缺少资金之类的原因被拒绝执行
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')
        # 订单状态处理完成，设为空
        self.order = None

    def notify_trade(self, trade):
        """
        交易成果

        Arguments:
            trade {object} -- 交易状态
        """
        if not trade.isclosed:
            return

        # 显示交易的毛利率和净利润
        self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                 (trade.pnl, trade.pnlcomm), doprint=True)



    def next(self):

        total_value = self.broker.getvalue()
        p_value = total_value*0.9/10



        for data in self.datas:
            # i=len(self.datas)
            self.orders[data._name] = None
            # 为每个数据定义字典，存储技术指标
            self.inds[data] = dict()


            #print(data.datetime[0])
            pos = self.getposition(data).size
            #data.close[0] > data.N_High[0] and data.rsi <50 and
            if not pos :
                #if  data.rsi <30 and data.close[-4]<data.lines.bot[-4] and data.close[-3]<data.lines.bot[-3] and data.close[-2]<data.lines.bot[-2] and data.close[-1]>data.lines.bot[-1]  :
                zd = ((data.close[0]  - data.open[0])/data.low[0])*100

                if (( data.J[0]<10 and data.J[-1]<data.J[0] and data.sma2[0]  > data.high[0] and data.close[0]  > data.open[0] )):
                #        if data.wave[0] <200 and data.wave[0]  < data.wave_two[0] and data.wave_two[0] < data.wave_three[0]:
                            #and   data.sma2[0] > data.close[0] and data.sma2[0] > data.open[0] and
                            print(data._name,'',data.datetime.date(0))
                            self.order = self.buy ( data=data )
                            data.profit = 1
            elif not self.orders[data._name]:
                # 下保护点卖单
                self.orders[data._name] = self.close(data = data, exectype= bt.Order.StopTrail,
                            trailamount=self.p.trailamount,
                            trailpercent=self.p.trailpercent)

            #if pos!=0 :
            #    if  data.profit == 1:
            #        self.close ( data = data )
                    #print(data._name, '', data.datetime.date(0))
            #        data.profit = 0
    def log(self, txt, dt=None,doprint=False):
        if self.params.printlog or doprint:
            dt = dt or self.datas[0].datetime.date(0)
            print(f'{dt.isoformat()},{txt}')

    #  or self.getFrontB( data, 3) == True


    def getFrontB(self, data,  end):
        for i in range(1, end):
            if data.close[-i] > data.close[-(i+1)]:
                return False
        return True



